perm filename PARM.PAL[PNT,HE]17 blob
sn#613443 filedate 1981-09-15 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00017 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00003 00002 put locations into comtab
C00004 00003 routines to set up coefficients for drive
C00011 00004 ROUTINE TO READ RAW FORCE WRIST AND RETURN INFORMATION TO PDP10
C00013 00005 setspeed
C00014 00006 COMMENT correspondence between routines
C00015 00007 OUTSTX,scamul,addvec
C00018 00008 HLDPUM,UNCALIB
C00019 00009 KBDRTN :for calling keyboad routines
C00021 00010 CRTRTN: Keyboard controller in cartesian mode
C00026 00011 [CRTRTN: CONTINUATION]
C00030 00012
C00035 00013 JNTRTN: Joint motions via the keyboard.
C00040 00014 [JNTRTN: CONTINUATION]
C00044 00015 FRERTN: Frees up a joint
C00046 00016 GRARTN: Gravity model experimentation.
C00050 00017 DATA
C00051 ENDMK
C⊗;
;put locations into comtab
DATA
PUTLOC LSETSPEED,SETSPEED
PUTLOC LRFORCE, RFORCE
PUTLOC LDRV0,DRV0
PUTLOC LDRIVE,DRIVE
PUTLOC LUSTPPTR,USTPPTR
PUTLOC LLSTPPTR,LSTPPTR
PUTLOC LUNCALIB,UNCALIB
USTPPTR:
YUSTOP: YELPTR USTOP ;POINTERS YELLOW ARM JOINT ANGLE UPPER LIMITS
BUSTOP: BLUPTR USTOP ; " BLUE " " " " "
HUSTOP: HDVPTR USTOP ; " HARDWARE " " " "
LSTPPTR:
YLSTOP: YELPTR LSTOP ;POINTERS YELLOW ARM JOINT ANGLE LOWER LIMITS
BLSTOP: BLUPTR LSTOP ; " BLUE " " " " "
HLSTOP: HDVPTR LSTOP ; " HARDWARE " " " "
CODE
; routines to set up coefficients for drive
; DRV0 is a routine that computes the appropriate coefficients
; given the arm and joint number and the amount of motion and
; whether it is absolute or relative.
; AC0 = some amount
; r3 = joint number
; r1 = arm number
; r2 = absolute (1) or relative (0)
⊗
DRV0: MOV R4,-(SP)
MOV R5,-(SP)
MOV R0,CFLST ; save coeff list address
MOV R3,JOINT
MOV R0,R3 ; r3 now will build up polylist
MOV R2,ABSDRV ; save r2
STF AC0,JTAMT ; save r0
TST R1 ; check which arm
BEQ 1$ ; skip if yellow
MOV #4,R0 ;THIS IS BLUE ARM JOINT 7 SERVO BIT
BR 2$
1$: MOV #1000,R0 ;THIS IS YELLOW ARM JOINT 7 SERVO BIT
2$: MOV #7,R1 ;R1←7
SUB JOINT,R1 ;R1←7-JOINT NUMBER
ASH R1,R0 ;SHIFT BIT TO INDICATE PROPER JOINT
MOV R0,(R3)+ ;SET SERVO BIT
CLR (R3)+ ;zero next servo word
CLR (R3)+ ;no special word
CLR (R3)+ ;no wobble
MOV #40.,(R3)+ ;rel segment pointer
MOV #2000.,(R3)+ ;SET DURATION OF DRIVE MOTION = 2000 MSEC
CLR (R3)+ ; no trans
CLR (R3)+ ;no run code
MOV R3,-(SP) ; save the address so far
;SET UP THE DYNAMIC COEFFICIENT LIST CI AND CII
BIT #YARM+YHAND,@CFLST ;CHECK IF THIS IS FOR THE YELLOW ARM
BEQ NOYEL
MOV #YARM+YHAND,WLST ;IF SO, READ THE CURRENT JOINT ANGLES
MOV #YELARM,R2 ;INDICATE YELLOW ARM
MOV #YTH,R4 ;GET POINTER TO YELLOW JOINT ANGLES
BR FILLAN
;*k could be vise too
NOYEL: MOV #BARM+BHAND,WLST ;ELSE MUST BE BLUE ARM
MOV #BLUARM,R2 ;INDICATE BLUE ARM
MOV #BTH,R4 ;GET POINTER TO BLUE JOINT ANGLES
FILLAN: MOV #WLST,R0
MOV #DEVICE,R1
JSR PC,WHERE
BIT #YHAND+BHAND,@CFLST ;CHECK IF HAND SELECTED FOR DRIVE
BNE ISHND ;BRANCH IF HAND OPERATION
MOV JOINT,R3 ;GET POINTER TO JOINT ANGLE
DEC R3
ASH #1,R3
ADD R4,R3
LDF JTAMT,AC0
LDF @(R3),AC1 ;AC1←OLD VALUE
STF AC1,JTOLD ;save old value of joint
TST ABSDRV
BEQ 2$ ; branch because relative
SUBF AC0,AC1 ;AC1←DIFFERENCE
NEGF AC1
STF AC1,JTDIF
BR 3$
2$: STF AC0,JTDIF
3$: MOV R4,R0 ;COMPUTE CORRESPONDING ARM DYNAMIC COEFFICIENTS
MOV #CIPTR,R1
JSR PC,DTERMS
MOV JOINT,R3 ;GET INDEX TO DYNAMIC COEFFICIENTS
ASH #2,R3
LDF CILST-4(R3),AC0 ;PICK UP GRAVITY LOADING AND INERTIA
STF AC0,SEGCI
LDF CIILST-4(R3),AC0
STF AC0,SEGCII
MOV #WLST,R0 ;RESTORE CURRENT JOINT ANGLES
MOV #DEVICE,R1
JSR PC,WHERE
BR DODRVE
ISHND:
BIT #YHAND,@CFLST ;CHECK IF YELLOW HAND
BEQ NOYHND
LDF CI+SRV07,AC0 ;IF YELLOW GET PROPER CI AND CII
LDF CII+SRV07,AC1
BR DOHAND
NOYHND: BIT #BHAND,@CFLST ;CHECK IF BLUE HAND
BEQ NOBHND
LDF CI+SRV14,AC0 ;IF BLUE GET PROPER CI AND CII
LDF CII+SRV14,AC1
BR DOHAND
NOBHND: BIT #VISE,@CFLST ;CHECK IF VISE
BEQ NOVISE
; LDF CI+SRV15,AC0 ;IF VISE GET PROPER CI AND CII
; LDF CII+SRV15,AC1
BR DOHAND
;;; should not come here
NOVISE:
;; MOV #NSCR,R0 ;SAY LOOKING FOR SCREWDRIVER
;; JSR PC,TYPSTR
;; DISMIS
DOHAND: STF AC0,SEGCI ;PUT DYNAMIC COEF. IN DATA LIST
STF AC1,SEGCII
;fill up rest of coefficients
DODRVE: MOV (SP)+,R3 ;restore state of coef list
MOV #6,R1
4$: CLR (R3)+ ;next tHREE coeffs=0
SOB R1,4$
LDF JTDIF,AC0 ;GET THE CHANGE IN JOINT ANGLE
LDF C10,AC1 ;SCALE 5TH ORDER POLYNOMIAL BY CHANGE AND PACK
MULF AC0,AC1 ; IN TO COEFFICIENT DATA LIST
STF AC1,(R3)+
LDF CM15,AC1
MULF AC0,AC1
STF AC1,(R3)+
LDF F6,AC1
MULF AC0,AC1
STF AC1,(R3)+
LDF SEGCI,AC0
STF AC0,(R3)+
LDF SEGCII,AC0
STF AC0,(R3)+
CLR (R3)+
CLR (R3)+
MOV (SP)+,R5
MOV (SP)+,R4
RTS PC
DATA
ABSDRV: .WORD 0
JOINT: .WORD 0
JTDIF: .WORD 0
DEVICE: .BLKW 32 ;DEVICE BLOCK
CFLST: .WORD 0 ;coefficient list
SEGCI: .BLKW 2 ;CI
SEGCII: .BLKW 2 ;CII
WLST: 374 ;JOINT SERVO BIT
0
C10: .WORD 41040,0 ;10.0
CM15: .WORD 141160,0 ;-15.0
F6: .WORD 40700,0 ;6.0
;TABLES FOR COMPUTE DYNAMIC COEFFICIENTS
CIPTR: CILST
CILST+4
CILST+10
CILST+14
CILST+20
CILST+24
CIILST
CIILST+4
CIILST+10
CIILST+14
CIILST+20
CIILST+24
CILST: .BLKW 12.
CIILST: .BLKW 12.
JTOLD: .WORD 0
JTAMT: .WORD 0,0
NSCR: .ASCIZ /LOOKING FOR THE SCREWDRIVER
/
CODE
;ROUTINE TO READ RAW FORCE WRIST AND RETURN INFORMATION TO PDP10
; copied over from old POINTY file
; note that the data sent is in integer format
;
; procedure should be called with R1 containing a pointer to
; the buffer in which the data is to be stored.
; sample call is as follows:
;
; MOV #FPPTR,R1
; JSR PC,RFORCE
;
; R0,R2 will be garbaged.
; FPPTR will be updated
;
RFORCE: MOV R3,-(SP) ;save registers
MOV R4,-(SP)
MOV R1,-(SP)
MOV (R1),R1 ;now R1 has address instead of address of address
MOV #10.,R2 ;READ 10 SETS OF DATA
SETLP: MOV #9.,R3 ;EIGHT STRAIN GAGES IN ALL+REF CHAN
MOV #30,R4 ;FIRST STRAIN GAGE CHANNEL
REDLP: MOVB R4,ADCCHN ;START CONVERTING STRAIN GAGE READING
WLP: TSTB ADCSR ;WAIT TILL CONVERSION COMPLETED
BMI CNVDNE
BR WLP
CNVDNE: MOV ADCVAL,R0 ;GET READING FROM BLUE INTERFACE
; ADD #2048.,R0
MOV R0,(R1)+ ;SAVE READING
INC R4 ;POINT TO NEXT CHANNEL
SOB R3,REDLP ;REPEAT UNTIL DONE
CLR -2(R1) ;NO REFERENCE READING
SOB R2,SETLP ;DO IT 10. TIMES
MOV (SP)+,R0 ;now update the pointer value
MOV R1,(R0)
MOV (SP)+,R4 ;retrieve registers
MOV (SP)+,R3
RTS PC
; setspeed
SETSPEED:
STF AC0,SPEED ; change the speed factor
RTS PC
DATA
SPEED: .FLT2 2.0 ;DEFAULT SPEED FACTOR
CODE
COMMENT ⊗ correspondence between routines
ARM.PAL WAVARM.PAL[PUM,HE],WAVSUP.PAL[PUM,HE],ETC
MOVPUM MOVEIT
PANGLE ANGLES
UPDATE WHERE
SOLVE SOLVE
EVPUMA MOVARM
BITON/OFF BITON/OFF
WVECT,RVECT WVECT,RVECT
⊗ ;
DATA
PUTLOC LKBDRTN,KBDRTN
CODE
; OUTSTX,scamul,addvec
.MACRO OUTSTX B ;type string starting at B
MOV #B,R0 ;Load up the string to be output
JSR PC,@LTYPSTR ;Call the string output utility routine
.ENDM
; INCHRI looks at the terminal. If a char is there, it gets put in R0, else
; R0 is cleared to mean no char yet. This differs from the INCHR in
; ALIO in that this does not wait for a character, and the character is
; returned in R0. It also echoes the character
INCHRI: MFPD OUTSW ;Where does it come from?
TST (SP)+
BEQ 1$
TSTB KBIS ;Anything typed on VT05?
BPL 2$ ; No
MOVB KBIR,R0 ; Read the char
BIC #177600,R0 ;Clear all but low 7 bits
JSR PC,@LTYPCHR ;Type the character
RTS PC
1$: MFPD IREG ;Anything from the 10?
MOV (SP)+,R0
BEQ 2$ ; No
CLR -(SP)
MTPD IREG ; Fetch the char
BIC #177600,R0
RTS PC
2$: CLR R0 ;No input
RTS PC
;SCAMUL performs a scalar multiply: multiplies the vector (R0) by AC0.
SCAMUL: PUSHF AC1
PUSH R5
MOV #3,R5
1$: LDF (R0),AC1 ;Get component
MULF AC0,AC1 ;and multiply by the scalar
STF AC1,(R0)+ ;Store back
SOB R5,1$
POP R5
POPF AC1
RTS PC
;ADDVEC adds the vector (R0) to (R1).
ADDVEC: PUSHF AC0
PUSH R5
MOV #3,R5 ;Vector has 3 components
1$: LDF (R1),AC0 ;Get component of 2nd vector
ADDF (R0)+,AC0 ;Add component of 1st to it
STF AC0,(R1)+ ; and store back
SOB R5,1$
POP R5
POPF AC0
RTS PC
; HLDPUM,UNCALIB
HLDPUM: MOV DANGLE,R0 ;reads current puma position and holds it there
MOV SRVDAT,DAT
JSR PC,PANGLE ;update the angles
PUSH <R2,R3,R4,R5>
MOV DANGLE,R0 ; go back to position mode with desired position
MOV SRVDAT,DAT
JSR PC,MOVPUM
POP <R5,R4,R3,R2>
RTS PC
UNCALIB:CLR CALFLG+SRV17 ;Clears "calibrated" flags for both Puma's
CLR CALFLG+SRV19
RTS PC
;KBDRTN :for calling keyboad routines
KBDRTN: MOV R1,MECHNO
CMP R1,#GRNARM ; find appropriate index for table pointer
BEQ 2$ ; is it garm?
MOV #2,R1 ; no, it must be red
BR 3$
2$: CLR R1 ; yes, it's green
3$: MOV DDANGLE(R1),DANGLE ; set appropriate values in dangel and srvdat
MOV DSRVNUM(R1),SRVDAT
ADD R0,R0
MOV 1$(R0),R0 ; get address of routine to jump to
PUSH <R2,R3,R4>
MOV #1,EXACT ; to allow different modes of arm solution
; to have closest orientation etc
JSR PC,(R0)
CLR EXACT ; as it was
POP <R4,R3,R2>
RTS PC
DATA
1$: .WORD FRERTN ; free it
.WORD JNTRTN ; joint control
.WORD TBLRTN ; cartesian control
.WORD TULRTN ; tool control
.WORD GRARTN ; gravity free
DDANGLE:.WORD GTH,RTH
DMECHNO:.WORD GRNARM,REDARM
DSRVNUM:.WORD SRV17,SRV19
CODE
; CRTRTN: Keyboard controller in cartesian mode
TBLRTN: OUTSTX KBDMS1
OUTSTX KBDWRL
CLR KMODE ; KMODE←0
BR CRTRTN
TULRTN: OUTSTX KBDMS1
OUTSTX KBDTUL
MOV #2,KMODE ; KMODE←2
CRTRTN: CLR MOVFLG ;1=ARM IS MOVING
CLR CHRCNT ;RESET # OF CHARS TYPED.
LDF FLT2,AC0 ;Re-calculate linear length in case it got changed
DIVF CYCRAT,AC0 ; LinearLength = LinearSpeed/CycleRate
STF AC0,LINLEN
KGET0: MOV DANGLE,R0 ;Where to put joint angles
MOV SRVDAT,DAT ;
JSR PC,PANGLES ;Read encoders, convert to angles, store in DANGLE
MOV #JTRES,R0 ;R1 points to result.
MOV #THPTR,R1 ;Prepare for call to solution routine. R0 ← angles
MOV MECHNO,R2
JSR PC,UPDATE ;Get backwards solution.
KGET: JSR PC,INCHRI ;Any new command typed?
TST R0
BEQ 50$ ;If not, br
INC CHRCNT ;ADD TO # OF CHARS ON THE LINE
CMP CHRCNT,CHRMAX
BLE 3$
PUSH R0
OUTSTX CRLFX
CLR CHRCNT
POP R0
3$: MOV #KBDTBL,R1 ;SET R1 TO 1ST ENTRY IN CMD TABLE
MOVB R0,KBDEND ;SET LAST ENTRY TO THE CMD LETTER (FOR A TRAP)
5$: CMPB (R1),R0 ;DOES IT MATCH THE INPUT?
BEQ 10$ ;IF SO, QUIT
ADD #6,R1 ;TO NEXT ENTRY
BR 5$
10$: MOV 2(R1),R0 ;GET ADDR OF DIRECTION VECTOR OR ROUTINE
TST R0 ;IF NOT FOUND IN TABLE
BGE 20$ ;THEN COMPLAIN NOW
OUTSTX WHAT
CLR MOVFLG ;ARM IS NOT MOVING ANY MORE
BR KGET
20$: TST 4(R1) ;IS THIS A MOTION COMMAND?
BNE 30$ ;YES - GO COPY DIRECTION VECTOR
JMP (R0) ;NO - GO TO ROUTINE
30$: MOV KMODE,R0
MOV DIRADR(R0),R0 ;R0 has address of appropriate vector
ADD 2(R1),R0 ;add offset into vector table to get direction
MOV 4(R1),R2 ; (save +/- sense of vector in R2)
MOV #DIREC,R1 ;COPY DIRECTION VECTOR
MOV #3,R3
JSR PC,CPYFLT
LDF LINLEN,AC0 ; linear segment to get segment components.
TST R2 ; motion in +ve direction
BGT 40$
NEGF AC0 ;negative motion
40$: MOV #DIREC,R0 ; multiply direction vector by length of each deg
JSR PC,SCAMUL
INC MOVFLG ;MEANS ARM IS MOVING NOW.
BR KDOIT ;Go move the arm.
50$: TST MOVFLG ;IS THE ARM MOVING? IF NOT,
BEQ KGET ; then keep look till we get a command
KDOIT: MOV #DIREC,R0 ;Now add increment vector to current position
MOV #JTRES+PX,R1 ; set 2nd operand = P vector
JSR PC,ADDVEC ; add two vectors (result into P)
MOV MECHNO,R2
MOV #THPTR,R1
MOV #JTRES,R0
JSR PC,SOLVE ; now go do an arm solution
TSTB R0 ;SOL'N FOUND?
BNE 5$ ;If not, br & report
BIT #FARBIT,R0 ;GOT FAR SOLUTION??
BEQ 1$ ;IF CLOSE SOL'N, BR - OK
OUTSTX WATCH ;SAY GOT FAR SOL'N
JMP KSTOP
5$: BIC #177400,R0 ;CLEAR HIGH BITS IF SET.
; BIS #NOSOLN,R0 ;NO, TYPE BAD JOINT NUMBER
OUTSTX BADSOL ;PRINT ERROR MESSAGE - NO SOLUTION
JMP KSTOP ;STOP THE ARM BUT WAIT FOR MORE INPUT.
1$: MOV DANGLE,R0 ;SET ADDR OF ANGLES TO MOVE TO
MOV SRVDAT,DAT
JSR PC,MOVPUM ;MOVE THE ARM TO DESIRED POSITION.
11$: TST R1
BEQ 2$ ;IF ERROR DURING MOVE, QUIT
JMP KSTOP
2$: SLEEP #12 ;otherwise sleep for 10 msec
JMP KGET
; [CRTRTN: CONTINUATION]
KSLOW: LDF FLT1,AC1 ;CALCULATE 1/KFACTR
DIVF KFACTR,AC1 ;FACTOR TO MULTIPLY BY INTO AC1.
BR RECALC
KFAST: LDF KFACTR,AC1 ;MULTIPLICATION FACTOR
RECALC: LDF LINSPD,AC0 ;INCREASE THE SPEED
MULF AC1,AC0
STF AC0,LINSPD ;Store new linear speed.
DIVF CYCRAT,AC0 ; LinearLength = LinearSpeed/CycleRate
STF AC0,LINLEN
STF AC1,AC0 ;Factor to multiply LinearLength by.
MOV #DIREC,R0 ;Multiply Direction vector by length of each
CALL SCAMUL ; segment to get length of each component.
JMP KGET
KOPEN: MOV #AIROPN,R0 ;Set bit to open hand
BR KHAND
KCLOSE: MOV #AIRCLS,R0 ;Bit to close hand
KHAND: MOV SRVDAT,DAT
BIC #AIROPN+AIRCLS,ARMBIT(DAT)
CALL BITON ;Set bit in R0 on in joint 7 status word
JMP KGET
KTOOL: MOV #2,KMODE
BR KCHGM
KWORLD: CLR KMODE
KCHGM: CLR MOVFLG
JMP KGET0
KSTOP: CLR MOVFLG ;NO LONGER MOVING
JMP KGET
CQUIT: CLR R1
RTS PC ;EXIT
;CPYFLT: COPIES R3 FLOATING NUMBERS FRO (R0) TO (R1). ALL REGS USED ARE CHANGED.
CPYFLT: MOV (R0)+,(R1)+
MOV (R0)+,(R1)+
SOB R3,CPYFLT
RTS PC
DATA
KMODE: .WORD 0 ; mode of motion 0=table, 2=tool
LINLEN: .FLT2 0 ;CALCULATED
LINSPD: .FLT2 2.0 ;2 INCHES PER SECOND
DIRADR: .WORD WRLDIR,JTRES
DIREC: .BLKW <3*4>
JTRES: .BLKW <3*4*2>
KBDMS1: .ASCIZ /
KEYBOARD CONTROL MODE /
KBDTUL: .ASCIZ /(TOOL MODE): /
KBDWRL: .ASCIZ /(WORLD MODE): /
ERRMES: .ASCIZ /ERROR FOUND
/
FARMSG: .ASCIZ / ** TRAJ SOLN INVALID **/
WATCH: .ASCIZ / πSINGULAR SOLUTION ... /
BADSOL: .ASCIZ / π** NO SOLUTION **/
.EVEN
KBDTBL: .ASCIZ /A/ ;COMMAND = A = SLOW DOWN
.WORD KSLOW,0 ;ROUTINE ADDR & 0=NOT MOTION COMMAND.
.ASCIZ /S/ ;for a motion command, 2nd word is offset
.WORD AX,-1 ;into direction vector tbl, 3rd is +1/-1 for
.ASCIZ /D/ ;direc
.WORD OX,-1
.ASCIZ /F/
.WORD NX,-1
.ASCIZ /J/
.WORD NX,1
.ASCIZ /K/
.WORD OX,1
.ASCIZ /L/
.WORD AX,1
.ASCIZ /;/
.WORD KFAST,0
.ASCIZ /Q/
.WORD CQUIT,0
.ASCIZ / /
.WORD KSTOP,0
.ASCIZ /O/
.WORD KOPEN,0
.ASCIZ /C/
.WORD KCLOSE,0
KBDEND: .WORD 0,-1,0
KFACTR: .FLT2 1.6 ;SPEED CHANGE FACTOR
FLT2: .FLT2 2.0 ;DEFAULT SPEED, INCHES/SEC
F1000: .FLT2 1000.0
WRLDIR: .FLT2 1,0,0 ; DIRECTION FOR X-AXIS IN WORLD
.FLT2 0,1,0 ; and Y-asix
.FLT2 0,0,1 ; and Z-axis
MAXSPD: .FLT2 30.0, 35.0, 35.0, 1.00, 35.0, 35.0 ;Max speed for each joint
SPDFAC: .FLT2 1.0 ;SPEED FACTOR.
CODE
COMMENT ⊗
; MOVARM: Servoes arm to position in DANGLE
; For 5th degree poly. interolation, with speed=accel.=0 at endpoints, we use
; p = p0 + 10*del*t↑3 - 15*del*t↑4 + 6*del*t↑5
; where del=(final-initial), and t=time/T, with T=total time for move.
MOVARM: PUSH <R0,R2,R3,R4>
PUSHF AC0
PUSHF AC1
MOV #NJTS,R4 ;Figure out how many segments needed for this move
MOV #CANGLES,R0
MOV SRVDAT,DAT
JSR PC,PANGLE ;Current angles in INITH
CLR R0
CLRF AC1 ;This will be max. time for a joint to do its move
MOV DANGLE,R2 ; R2 is starting address of final angles computed
;HACK
5$: CMP R0,#14 ;Is this joint 4? If so, ignore it
BEQ 7$
LDF @(R2)+,AC0
STF AC0,FTH(R0)
SUBF INITH(R0),AC0 ;Get final-initial angle = change needed.
STF AC0,DIFF(R0) ;Store partial result (final-initial) in INCR
ABSF AC0 ; (and get absolute value of change)
DIVF MAXSPD(R0),AC0 ;Get how many seconds req'd for joint to move
COMPF AC0,AC1 ;Is time < max? If so, ignore & keep current max
BLE 7$
STF AC0,AC1 ;Save new max. time
7$: CMP (R0)+,(R0)+
SOB R4,5$
MULF SPDFAC,AC1 ;Include the speed factor too.
MULF CYCRAT,AC1 ;Multiply time by (60) to get number of segments
STCFI AC1,R4
TST R4 ;If it's zero, make it one.
BNE 8$
INC R4
8$: LDCIF R4,AC1 ;Now number of segments is an integer, in AC1
; Now move the arm. Move with number of segments in AC1 (and R4).
; Move each joint by using the polynomial
; p(t) = p0 + diff*t↑3*(10 + t*(-15 + 6*t)), with t=time/TotalTime.
10$: MOV #NJTS,R3 ;Go thru & calculate the polys for each joint
MOV DANGLE,R2
CLR R0
15$: LDCIF R4,AC0 ;Get what time it is
NEGF AC0 ;Convert to the range [0,1]
ADDF AC1,AC0
DIVF AC1,AC0 ;t is now in AC0.
STF AC0,AC3 ;Calculate 6*t
MULF FLT6,AC3
SUBF FLT15,AC3 ;AC3 = 6*t - 15
MULF AC0,AC3 ; = t(6t-15)
ADDF FLT10,AC3 ; = 10 + t(6t-15)
MULF AC0,AC3 ; = t(10 + t(6t-15))
MULF AC0,AC3 ; = t↑2(10 + t(6t-15))
MULF AC0,AC3 ; = t↑3(10 + t(6t-15))
MULF DIFF(R0),AC3 ; = diff*t↑3(10 + t(6t-15))
ADDF INITH(R0),AC3 ; = p0 + ...
STF AC3,@(R2)+ ; (store back into current angle)
CMP (R0)+,(R0)+
SOB R3,15$
; Now we know (in DANGLE) where to move the arm. So move it now.
MOV DANGLE,R0 ;Make arm move to angles which are in DANGLE.
PUSH R4
PUSHF AC1
MOV SRVDAT,DAT
JSR PC,MOVPUM ;Move arm to angles in DANGLE
POPF AC1
POP R4
TST R1 ;If error during move, quit
BNE 50$
SLEEP #10. ; otherwise sleep
SOB R4,10$ ;Do as many times as there are segments.
50$: POPF AC1
POPF AC0
POP <R4,R3,R2,R0>
RTS PC
⊗ ;
DATA
FLT6: .FLT2 6.0
FLT15: .FLT2 15.0
FLT10: .FLT2 10.0
CODE
; JNTRTN: Joint motions via the keyboard.
; Makes the VT05 act as a joint-mode teachbox (joystick).
JNTRTN: OUTSTX JMSG1 ;TYPE MESSAGE
CLR MOVFLG ;0=ARM IS NOT MOVING
CLR CHRCNT ;RESET # OF CHARS TYPED.
LDF JINTSP,AC0 ;Re-calculate degrees/cycle in case it got changed
STF AC0,JNTSPD ;Joint speed - save it.
DIVF CYCRAT,AC0 ; Degrees/Cycle = Degrees/sec / Cycles/sec
STF AC0,JDEGR ;Store degrees per cycle here.
MOV DANGLE,R0 ;Where to put joint angles
MOV SRVDAT,DAT
JSR PC,PANGLE ;Read encoders, convert to angles, store in DANGLE
JGET: JSR PC,INCHRI ;any new command typed?
TST R0
BEQ 50$ ;if not, branch
INC CHRCNT ;ADD TO # OF CHARS ON THE LINE
CMP CHRCNT,CHRMAX
BLE 3$
PUSH R0
OUTSTX CRLFX ;do a crlf
CLR CHRCNT
POP R0
3$: MOV #JNTTBL,R1 ;SET R1 TO 1ST ENTRY IN CMD TABLE
MOVB R0,JNTEND ;SET LAST ENTRY TO THE CMD LETTER (FOR A TRAP)
5$: CMPB (R1),R0 ;DOES IT MATCH THE INPUT?
BEQ 10$ ;IF SO, QUIT
ADD #6,R1 ;TO NEXT ENTRY
BR 5$
10$: MOV 2(R1),R0 ;GET ADDR OF ROUTINE
CMP R0,#-1 ;IF NOT FOUND IN TABLE
BNE 20$ ;THEN COMPLAIN NOW
OUTSTX WHAT
CLR MOVFLG ;ARM IS NOT MOVING ANY MORE
BR JGET
20$: TST 4(R1) ;IS THIS A MOTION COMMAND? 0=NO (ROUTINE)
BNE 30$ ;YES - GO SET UP DIRECTION VECTOR
JMP (R0) ;NO - GO TO ROUTINE
30$: MOV #JNTDIR,R0 ;NOW SET UP DIRECTION VECTOR. R0 TO VECTOR
MOV 4(R1),R2 ;PUT JOINT NUMBER IN R0 (FROM TABLE)
MOV #1,R1 ;R1 COUNTS THE JOINT NUMBER
35$: CLRF (R0) ;ASSUME ZERO
CMP R1,R2 ;IS THIS THE DIRECTION?
BNE 40$ ;NO - CONTINUE
MOV JDEGR,(R0) ;COPY DEGREES/SEGMENT INTO DIRECTION COMPONENT
MOV JDEGR+2,2(R0)
40$: CMP (R0)+,(R0)+ ;INCREMENT POINTER
INC R1 ;AND COUNTER
CMP R1,#6 ;END?
BLE 35$ ;NO - KEEP GOING
CLR MOVFLG ;MEANS ARM IS STOPPED.
MOV #1,JDIREC ;MOVE IN POSITIVE DIRECTION.
BR JGET ;Wait for + or - motion command before we move.
50$: TST MOVFLG ;IS THE ARM MOVING? IF NOT,
BEQ JGET ; then keep look till we get a command
BR JDOIT ; otherwise keep moving it.
JNEG: MOV #-1,JDIREC ;Means joint should go in - direction
BR JMOVE
JPOS: MOV #1,JDIREC ;Means joint should go in + direc.
JMOVE: INC MOVFLG ;Means arm is moving now.
MOV #JNTDIR,R0 ;Now make direction the right way.
MOV #NJTS,R1
3$: LDF (R0),AC0 ;Get current dir.
ABSF AC0 ;assume positive
TST JDIREC ;negative motion?
BPL 5$ ; no - br
NEGF AC0 ; yes - make it negative.
5$: STF AC0,(R0)+ ;
SOB R1,3$
JDOIT: MOV DANGLE,R0
MOV #NJTS,R1 ;Now add angle increments to DANGLE
MOV #JNTDIR,R2
1$: LDF @(R0),AC0
ADDF (R2),AC0
STF AC0,@(R0)+
CMP (R2)+,(R2)+
SOB R1,1$
MOV DANGLE,R0 ;SET ADDR OF ANGLES TO MOVE TO
MOV SRVDAT,DAT
JSR PC,MOVPUM ;MOVE THE ARM TO DESIRED POSITION.
TST R1
BNE JQUIT ;IF ERROR DURING MOVE, QUIT
SLEEP #16. ;SLEEP FOR 16 msec
JMP JGET
; [JNTRTN: CONTINUATION]
JSLOW: LDF FLT1,AC1 ;CALCULATE 1/JFACTR
DIVF JFACTR,AC1 ;FACTOR TO MULTIPLY BY INTO AC1.
BR JCALC
JFAST: LDF JFACTR,AC1 ;MULTIPLICATION FACTOR
JCALC: LDF JNTSPD,AC0 ;INCREASE/DECREASE THE SPEED
MULF AC1,AC0
STF AC0,JNTSPD ;Store new joint speed.
DIVF CYCRAT,AC0 ;Angle increment = JointSpeed / CycleRate
STF AC0,JDEGR
MOV #JNTDIR,R0 ;Now multiply direction vector by factor
MOV #NJTS,R1
5$: LDF (R0),AC0 ;Get current component
MULF AC1,AC0 ;Multiply by factor
STF AC0,(R0)+
SOB R1,5$
JMP JGET
JOPEN: MOV #AIROPN,R0 ;Set bit to open hand
BR JHAND
JCLOSE: MOV #AIRCLS,R0 ;Bit to close hand
JHAND: MOV SRVDAT,DAT
BIC #AIROPN+AIRCLS,ARMBIT(DAT)
CALL BITON ;Set bit in R0 on in joint 7 status word
JMP JGET
JSTOP: CLR MOVFLG ;NO LONGER MOVING
JMP JGET
JQUIT: CLR R1
RTS PC ;EXIT
DATA
JNTTBL: .ASCIZ /A/ ;COMMAND = A = SLOW DOWN
.WORD JSLOW,0 ;ROUTINE ADDR & 0=NOT MOTION COMMAND.
.ASCIZ /F/
.WORD JNEG,0 ;MOVE NEGATIVE
.ASCIZ /J/
.WORD JPOS,0 ;MOVE POSITIVE
.ASCIZ /;/
.WORD JFAST,0 ;MOVE FASTER
.ASCIZ /Q/
.WORD JQUIT,0
.ASCIZ / /
.WORD JSTOP,0
.ASCIZ /O/
.WORD JOPEN,0
.ASCIZ /C/
.WORD JCLOSE,0
.ASCIZ /1/ ;1=MOVE JOINT 1
.WORD 0,1
.ASCIZ /2/
.WORD 0,2
.ASCIZ /3/
.WORD 0,3
.ASCIZ /4/
.WORD 0,4
.ASCIZ /5/
.WORD 0,5
.ASCIZ /6/
.WORD 0,6
JNTEND: .WORD 0,-1,0 ;END OF TABLE
JINTSP: .FLT2 4.0 ;INITIAL JOINT SPEED (DEGR/SEC)
JFACTR: .FLT2 1.6 ;SPEED CHANGE FACTOR
JDEGR: .FLT2 0.0 ;DEGREES PER CYCLE
JNTDIR: .BLKW <2*NJTS> ;DIRECTION OF MOTION
JDIREC: .BLKW 1 ;1 OR -1 FOR POSITIVE/NEGATIVE MOTION
JNTSPD: .FLT2 2.0 ;JOINT SPEED - DEGREES/SEC.
CHRCNT: .WORD 0
CHRMAX: .WORD 30.
CYCRAT: .FLT2 60.0 ;HOW MANY CYCLES PER SECOND
MOVFLG: .WORD 0 ;1=puma moving
WHAT: .ASCIZ /?? /
JMSG1: .ASCIZ /
JOINT CONTROL MODE: /
BADJT: .ASCIZ /
BAD JOINT/
.EVEN
CODE
; FRERTN: Frees up a joint
; this routine garbages R0 and R1
FRERTN: OUTSTX FREMS1 ;ASK WHICH JOINT TO FREE UP
JSR PC,@LINCHR ; R1←response
PUSH R1
MOV R1,R0
JSR PC,@LTYPCHR ; echo it
OUTSTX CRLFX
POP R1
SUB #60,R1 ;MAKE IT AN INTEGER.
CMP R1,#1 ;VALIDATE THE INPUT
BLT 10$
CMP R1,#6
BLE 20$
10$: OUTSTX FREMS2 ;INVALID INPUT message
BR 100$
20$: DEC R1 ; transform 1 - 6 to 0-5
ADD #10,R1 ;ADD 10 ==> CURRENT MODE
CLR R0 ;DATA = 0 ==> NO TORQUE
MOV SRVDAT,DAT
JSR PC,WSINGL ;FREE UP THE JOINT!
OUTSTX FREMS3 ; print type any char to stop
JSR PC,@LINCHR ;R1←charcter
MOV R1,R0
JSR PC,@LTYPCHR ;echo it
OUTSTX CRLFX
JSR PC,HLDPUM ; hold puma in current position
OUTSTX FREMS4
100$: OUTSTX CRLFX
RTS PC
DATA
FREMS1: .ASCIZ /
FREE UP JOINT# (1-6): /
FREMS2: .ASCIZ /
SORRY, BAD JOINT #/
FREMS3: .ASCIZ /
TYPE ANY CHAR TO STOP: /
FREMS4: .ASCIZ /
-- STOP FREE./
CRLFX: .ASCIZ /
/
.EVEN
CODE
; GRARTN: Gravity model experimentation.
GRARTN: OUTSTX GRAMS1 ;Type informative msg
OUTSTX GRAMS2 ;Say arm is free (even though it isn't yet)
10$: MOV DANGLE,R0 ;Read joint angles & put in dangle
MOV SRVDAT,DAT
JSR PC,PANGLES
JSR PC,INCHRI ; see if character typed
TST R0 ;Was a char typed?
BNE 50$ ;If so, quit now.
JSR PC,GCALC ;Calculate torques needed to keep arm steady
MOV #TRQUE,R0 ;Set address of torques to apply
MOV #CURRNT+SEQMDE,R1 ;Current mode for all joints
MOV SRVDAT,DAT
JSR PC,WVECT ;Enter current mode!
SLEEP #10. ;Wait a little while (10 msec)
BR 10$ ;Do it again.
50$: JSR PC,HLDPUM ; hold pumas in current position
OUTSTX GRAMS3 ;Type msg upon return.
GRARET: RTS PC
JJ1==TH1*2
JJ2==TH2*2
JJ3==TH3*2
JJ4==TH4*2
JJ5==TH5*2
JJ6==TH6*2
GCALC: CLRF KANGLE+JJ1 ;No torque for joint 1
MOV DANGLE,R0
LDF @TH2(R0),AC0 ;For joint 2, torque = Ag*sin2 + Bg*sin23
ADDF FLT90,AC0 ;Account for different joint angle offset
JSR PC,SNCOS
STF AC0,GSIN2
LDF @TH3(R0),AC0 ;Theta3 = theta3 - 90
ADDF @TH2(R0),AC0 ;Theta23 = (theta3-90) + (theta2+90) = theta2+3
JSR PC,SNCOS
STF AC0,GSIN23
LDF GSIN2,AC0 ;Now calculate torque as above.
MULF GRAG,AC0
LDF GSIN23,AC1
MULF GRBG,AC1
ADDF AC1,AC0
STF AC0,KANGLE+JJ2 ;Store torque for joint 2
LDF GSIN23,AC0 ;Now calculate torque for joint 3.
MULF GRBG,AC0 ;Torque = B*g*sin23
STF AC0,KANGLE+JJ3
CLRF KANGLE+JJ4 ;No torque for the others joints.
CLRF KANGLE+JJ5
CLRF KANGLE+JJ6
MOV #NJTS,R3 ;Now convert torques into DAC units using
CLR R0 ; scale factors TSCALE.
CLR R1
10$: LDF KANGLE(R0),AC0 ;Get torque in oz-in.
MULF TSCALE(R0),AC0 ;Multiply by DAC/oz-in to get DAC's
STCFI AC0,TRQUE(R1) ;Put into final place
CMP (R0)+,(R0)+ ; (bump pointers)
TST (R1)+
SOB R3,10$
RTS PC
DATA
GRAMS1: .ASCIZ /
GRAVITY MODEL TESTER./
GRAMS2: .ASCIZ /
ARM SHOULD BE FREE NOW...TYPE ANY CHAR TO STOP: /
GRAMS3: .ASCIZ /
ALL DONE./
.EVEN
GRAG: .FLT2 16.5 ;This is A*g in JKS's model
GRBG: .FLT2 5.0 ;This is B*g in JKS's model
GSIN2: .FLT2 0.0 ;Sin(theta2)
GSIN23: .FLT2 0.0 ;Sin(theta2+theta3)
TRQUE: .WORD 0,0,0,0,0,0 ;TORQUES (FOR FORCE CONTROL MODE)
KANGLE: .FLT2 0,0,0,0,0,0 ;WORK AREA
TSCALE: .FLT2 9.2, 15.7, -11.0, 0.0, 0.0, 0.0 ;Torque scale factors
;(in DAC units per oz-in.)
CODE
DATA
DANGLE: .WORD GTH ;pointer to angle list
MECHNO: .WORD GRNARM
SRVDAT: .WORD SRV17
CANGLES:.WORD INITH,INITH+4,INITH+10,INITH+14,INITH+20,INITH+24,INITH+30
INITH: .BLKW 14.
FTH: .BLKW 14.
DIFF: .BLKW 14.
CODE